﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace MDS
{
    public struct SFITRecord
    {
        public const int SFITRecordLen = 337;
        private static Encoding _defaultEncoding = Encoding.Default;
        // public DMarketDataType type;

        //交易日期
        public String TradingDay;

        ////结算组代码
        //public String settlementGroupID;

        ////结算编号
        //public Int32 settlementID;

        /// <summary>
        /// 市场ID
        /// </summary>
        public FutureExchange Exch;

        /// <summary>
        /// 产品ID
        /// </summary>

        public String ProductID;

        //最新价
        public Double LastPrice;

        //昨结算
        public Double PreSettlementPrice;

        //昨收盘
        public Double PreClosePrice;

        //昨持仓量
        public Int64 PreOpenInterest;

        //今开盘价
        public Double OpenPrice;

        //最高价
        public Double HighestPrice;

        //最低价
        public Double LowestPrice;

        //数量
        public Int64 Volume;

        //成交金额
        public Double Turnover;

        //持仓量
        public Int64 OpenInterest;

        //今收盘
        public Double ClosePrice;

        //今结算
        public Double SettlementPrice;

        //涨停板价
        public Double UpperLimitPrice;

        //跌停板价
        public Double LowerLimitPrice;

        //昨虚实度
        public Double PreDelta;

        //今虚实度
        public Double CurrDelta;

        //最后修改时间
        public String UpdateTime;

        //最后修改毫秒
        public Int32 UpdateMillisec;

        //合约代码
        private String InstrumentID;

        public String StkId;

        //申买价一
        public Double BidPrice1;

        //申买量一
        public Int32 BidVolume1;

        //申卖价一
        public Double AskPrice1;

        //申卖量一
        public Int32 AskVolume1;

        //申买价二
        public Double BidPrice2;

        //申买量二
        public Int32 BidVolume2;

        //申卖价二
        public Double AskPrice2;

        //申卖量二
        public Int32 AskVolume2;

        //申买价三
        public Double BidPrice3;

        //申买量三
        public Int32 BidVolume3;

        //申卖价三
        public Double AskPrice3;

        //申卖量三
        public Int32 AskVolume3;

        //申买价四
        public Double BidPrice4;

        //申买量四
        public Int32 BidVolume4;

        //申卖价四
        public Double AskPrice4;

        //申卖量四
        public Int32 AskVolume4;

        //申买价五
        public Double BidPrice5;

        //申买量五
        public Int32 BidVolume5;

        //申卖价五
        public Double AskPrice5;

        //申卖量五
        public Int32 AskVolume5;


        public byte[] Serialize()
        {
            byte[] rtn = new byte[SFITRecordLen];
            int offset = 0;
            writeString(rtn, ref offset, TradingDay);
            writeString(rtn, ref offset, StkId);
            writeString(rtn, ref offset, Exch.ToString());
            writeString(rtn, ref offset, ProductID);
            writeDouble(rtn, ref offset, LastPrice);
            writeDouble(rtn, ref offset, PreSettlementPrice);
            writeDouble(rtn, ref offset, PreClosePrice);
            writeInt64(rtn, ref offset, PreOpenInterest);
            writeDouble(rtn, ref offset, OpenPrice);
            writeDouble(rtn, ref offset, HighestPrice);
            writeDouble(rtn, ref offset, LowestPrice);
            writeInt64(rtn, ref offset, Volume);
            writeDouble(rtn, ref offset, Turnover);
            writeInt64(rtn, ref offset, OpenInterest);//??
            writeDouble(rtn, ref offset, ClosePrice);
            writeDouble(rtn, ref offset, SettlementPrice);
            writeDouble(rtn, ref offset, UpperLimitPrice);
            writeDouble(rtn, ref offset, LowerLimitPrice);
            writeDouble(rtn, ref offset, PreDelta);
            writeDouble(rtn, ref offset, CurrDelta);
            writeString(rtn, ref offset, UpdateTime);
            writeInt32(rtn, ref offset, UpdateMillisec);
            writeDouble(rtn, ref offset, BidPrice1);
            writeInt64(rtn, ref offset, BidVolume1);
            writeDouble(rtn, ref offset, AskPrice1);
            writeInt64(rtn, ref offset, AskVolume1);
            writeDouble(rtn, ref offset, BidPrice2);
            writeInt64(rtn, ref offset, BidVolume2);
            writeDouble(rtn, ref offset, AskPrice2);
            writeInt64(rtn, ref offset, AskVolume2);
            writeDouble(rtn, ref offset, BidPrice3);
            writeInt64(rtn, ref offset, BidVolume3);
            writeDouble(rtn, ref offset, AskPrice3);
            writeInt64(rtn, ref offset, AskVolume3);
            writeDouble(rtn, ref offset, BidPrice4);
            writeInt64(rtn, ref offset, BidVolume4);
            writeDouble(rtn, ref offset, AskPrice4);
            writeInt64(rtn, ref offset, AskVolume4);
            writeDouble(rtn, ref offset, BidPrice5);
            writeInt64(rtn, ref offset, BidVolume5);
            writeDouble(rtn, ref offset, AskPrice5);
            writeInt64(rtn, ref offset, AskVolume5);
            return rtn;
        }
        
        private static void writeString(byte[] buff, ref int offset, string value)
        {
            if (!string.IsNullOrEmpty(value))
            {
                System.Text.Encoding.Default.GetBytes(value).CopyTo(buff, offset);
            }
            else
            {
                System.Text.Encoding.Default.GetBytes("000000000").CopyTo(buff, offset);
            }

            offset += 9;
        }
        private static void writeInt32(byte[] buff, ref int offset, Int32 value)
        {
            BitConverter.GetBytes(value).CopyTo(buff, offset);
            offset += 4;
        }
        private static void writeInt64(byte[] buff, ref int offset, Int64 value)
        {
            BitConverter.GetBytes(value).CopyTo(buff, offset);
            offset += 8;
        }
        private static void writeDouble(byte[] buff, ref int offset, Double value)
        {
            BitConverter.GetBytes(value).CopyTo(buff, offset);
            offset += 8;
        }

        public static SFITRecord Deserialize(byte[] data)
        {

            using (MemoryStream ms = new MemoryStream(data))
            {
                using (BinaryReader br = new BinaryReader(ms))
                {
                    SFITRecord rtn = new SFITRecord()
                    {
                        TradingDay = readString(br.ReadBytes(9)),
                        StkId = readString(br.ReadBytes(9)),
                        Exch = readString(br.ReadBytes(9)).FirstOrDefault(),
                        ProductID = readString(br.ReadBytes(9)),
                        LastPrice = br.ReadDouble(),
                        PreSettlementPrice = br.ReadDouble(),
                        PreClosePrice = br.ReadDouble(),
                        PreOpenInterest = br.ReadInt64(),
                        OpenPrice = br.ReadDouble(),
                        HighestPrice = br.ReadDouble(),
                        LowestPrice = br.ReadDouble(),
                        Volume = (Int32)(br.ReadInt64()),
                        Turnover = br.ReadDouble(),
                        OpenInterest = br.ReadInt64(),
                        ClosePrice = br.ReadDouble(),
                        SettlementPrice = br.ReadDouble(),
                        UpperLimitPrice = br.ReadDouble(),
                        LowerLimitPrice = br.ReadDouble(),
                        PreDelta = br.ReadDouble(),
                        CurrDelta = br.ReadDouble(),
                        UpdateTime = readString(br.ReadBytes(9)),
                        UpdateMillisec = br.ReadInt32(),
                        BidPrice1 = br.ReadDouble(),
                        BidVolume1 = (Int32)(br.ReadInt64()),
                        AskPrice1 = br.ReadDouble(),
                        AskVolume1 = (Int32)(br.ReadInt64()),
                        BidPrice2 = br.ReadDouble(),
                        BidVolume2 = (Int32)(br.ReadInt64()),
                        AskPrice2 = br.ReadDouble(),
                        AskVolume2 = (Int32)(br.ReadInt64()),
                        BidPrice3 = br.ReadDouble(),
                        BidVolume3 = (Int32)(br.ReadInt64()),
                        AskPrice3 = br.ReadDouble(),
                        AskVolume3 = (Int32)(br.ReadInt64()),
                        BidPrice4 = br.ReadDouble(),
                        BidVolume4 = (Int32)(br.ReadInt64()),
                        AskPrice4 = br.ReadDouble(),
                        AskVolume4 = (Int32)(br.ReadInt64()),
                        BidPrice5 = br.ReadDouble(),
                        BidVolume5 = (Int32)(br.ReadInt64()),
                        AskPrice5 = br.ReadDouble(),
                        AskVolume5 = (Int32)(br.ReadInt64())
                    };
                    return rtn;
                }
            }

        }

        private static string readString(byte[] buffer)
        {
            return _defaultEncoding.GetString(buffer);
        }
    }
}
